golang embed在windows中的一个坑

注意:这只是在windows下的问题!

当我在win下面构建一个自包含资源二进制包的时候,想要将一个res目录下的所有文件都嵌入进去,就像下面的代码一样。

//go:embed res/*
var efs embed.FS

data, err := efs.ReadFile(filepath.Join("res", "filename"))

但是却发现程序运行每次却读取不出数据,一开始以为//go:embed的语法上有错误,导致数据没有嵌入到exe中。就换了一个大文件实验一下看看二进制包的体积是否发生变化。

在验证exe文件在使用大文件后体积确实嵌入确实嵌入之后,检查一下文件路径,拷贝path出来cat一下文件也确实能访问得到。这就奇怪了?文件也嵌入进去了,路径也是对的为啥读取不到数据呢?正当我想开调试器逐行debug的时候,刚好扫了一眼路径感觉有点不对劲才发现了问题, 原来是正斜杆/和反斜杠\的锅。

windows在多年发展下,为了兼容linux的软件,正反斜杆都是合法的文件路径。在这种先入为主的思维下,我并没有看出路径的问题,因为在我的pwsh中去访问都是没有问题的。

但是问题就在于文件是嵌入在exe中,并且filepath是跨平台的,在windows下生成的路径自然用的是反斜杠\,emebed的fs用的是/,所以当然读取不到文件了。

修复的代码,只要用filepath.ToSlash将Join路径的反斜杠\变成/就好了。

data, err := efs.ReadFile(filepath.ToSlash(filepath.Join("res", "filename")))

其实严格意义上来讲这倒不是坑,本身golang的血统就是unix系,embed的路径用/来表示一点没问题都没有。只是filepah.Join是跨平台的,用的路径符号在win下当然就和unix系的冲突,只是windows现在对路径不区分正反斜杠的习惯性思维,才导致的这个"坑"。